#include "connectionpool.h"
#include "json.hpp"
#include <iostream>
#include <thread>
using json = nlohmann::json;
#include <fstream>

ConnectionPool *ConnectionPool::getConnectionPool()
{
    // 这种访问方式事线程安全的，因为静态变量是线程安全的
    static ConnectionPool pool;
    return &pool;
}

void ConnectionPool::ParseJsonFile()
{
    std::ifstream ifs("/home/ubuntu/mysqlstudy/dbconf.json");
    if (!ifs.is_open())
    {
        std::cerr << "Error opening file" << std::endl;
        return;
    }

    // 使用 nlohmann::json 解析 JSON 文件
    json config;
    ifs >> config;

    // 从 JSON 中提取数据并进行类型转换
    m_ip = config["ip"].get<std::string>();             // 这是字符串
    m_port = config["port"].get<int>();                 // 这是整数
    m_user = config["userName"].get<std::string>();     // 这是字符串
    m_password = config["password"].get<std::string>(); // 这是字符串
    m_dbname = config["dbName"].get<std::string>();     // 这是字符串
    m_minSize = config["minSize"].get<int>();           // 这是整数
    m_maxSize = config["maxSize"].get<int>();           // 这是整数
    m_maxIdleTime = config["maxIdleTime"].get<int>();   // 这是整数
    m_timeout = config["timeout"].get<int>();           // 这是整数
}

ConnectionPool::ConnectionPool()
{
    // 加载配置文件
    ParseJsonFile();

    for (int i = 0; i < m_minSize; i++)
    {
        addConnection();
    }
    // 生产连接
    std::thread producer(&ConnectionPool::produceConnection, this);

    // 销毁连接
    std::thread recycler(&ConnectionPool::recycleConnection, this);
    producer.detach();
    recycler.detach();
}

void ConnectionPool::produceConnection()
{
    while (true)
    {
        unique_lock<mutex> locker(m_mutex);
        while (m_connectionQ.size() >= m_maxSize) // 这里应该事m_maxSizse
        {
            m_cond.wait(locker);
        }
        // 在这里创建新连接
        addConnection();
        m_cond.notify_all();
    }
}
void ConnectionPool::recycleConnection()
{
    while (true)
    {
        this_thread::sleep_for(chrono::seconds(1));
        lock_guard<mutex> locker(m_mutex);
        while (m_connectionQ.size() > m_minSize)
        {
            MySqlConn *conn = m_connectionQ.front();
            if (conn->getAlieveTime() >= m_maxIdleTime)
            {
                m_connectionQ.pop();
                delete conn;
            }
            else
            {
                break;
            }
        }
    }
}

void ConnectionPool::addConnection()
{
    MySqlConn *conn = new MySqlConn();
    conn->connent(m_user, m_password, m_dbname, m_ip, m_port);
    conn->refreshAliveTime();
    m_connectionQ.push(conn);
}

shared_ptr<MySqlConn> ConnectionPool::getConnection()
{
    unique_lock<mutex> locker(m_mutex);
    while (m_connectionQ.empty())
    {
        // 让当前线程阻塞
        // 当阻塞时间超过 m_timeout 时，线程会被唤醒，但是会返回一个状态
        if (cv_status::timeout == m_cond.wait_for(locker, chrono::microseconds(m_timeout)))
        {
            // s说明任务队列还是为空
            if (m_connectionQ.empty())
            {
                continue;
            }
        }
    }
    // 任务队列不为空，则从队首取出一个任务
    // MySqlConn *conn = m_connectionQ.front();
    // 这句代码好好理解
    shared_ptr<MySqlConn> connptr(m_connectionQ.front(),[this](MySqlConn* conn){
        lock_guard<mutex> locker(m_mutex);
        conn->refreshAliveTime();
        m_connectionQ.push(conn);
    });
    /// 
    m_connectionQ.pop();
    // 唤醒生产者
    m_cond.notify_all();
    return connptr;
}

ConnectionPool::~ConnectionPool()
{
    for(int i = 0;i<m_connectionQ.size();i++)
    {
        MySqlConn* conn = m_connectionQ.front();
        m_connectionQ.pop();
        delete conn;
    }
}